﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;

namespace ReactiveCode.Observables
{
    interface IVariable
    {
        IObservable<object> Observe();
    }
    public sealed class Variable<T> : ISubject<T>, IObservableValue<T>, IVariable
    {
        ISubject<T> _listeners = new Subject<T>();
        public bool HasValue { get; private set; }
        T _value;
        public T Value
        {
            get { return _value; }
            set 
            {
                _value = value;
                HasValue = true;
                _listeners.OnNext(value);
            }
        }
        T IObservableValue<T>.Value
        {
            get { return Value; }
        }

        public Variable() { }
        public Variable(T value)
        {
            HasValue = true;
            _value = value;
        }
        
        public IDisposable Subscribe(IObserver<T> observer)
        {
            if (observer == null)
                throw new ArgumentNullException("observer");
            if (HasValue)
                observer.OnNext(Value);
            return _listeners.Subscribe(observer);
        }

        #region IObserver<T> Members

        void IObserver<T>.OnCompleted()
        {
        }

        void IObserver<T>.OnError(Exception error)
        {
            throw error;
        }

        void IObserver<T>.OnNext(T value)
        {
            Value = value;
        }

        #endregion

        IObservable<object> IVariable.Observe()
        {
            return this.Select(x => x as object);
        }

        public override string ToString()
        {
            return "{ " + Value + " }";
        }
    }
}
